tg-me.com/pyproglib/6772
Last Update:
До Python 3.7, если вы хотели создать объект Coordinate(x=1, y=2)
, приходилось писать:
class Coordinate:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
Это выглядело нормально. Но:
__init__
запускает код при каждом создании объекта, что усложняет работу, особенно если нужны побочные действия (например, открытие файла).Пример проблемного кода:
class FileReader:
def __init__(self, path: str):
self._fd = fileio.open(path)
Вроде удобно. Но:
fd
напрямую — нужно городить object.__new__
.fileio.open
.open
становится async
, вам уже не обойтись __init__
.Ключевая ошибка: связывать создание объекта с побочными эффектами (например, I/O) — это антипаттерн.
@dataclass
для объявления:@dataclass
class FileReader:
_fd: int # или лучше: FileDescriptor
@classmethod
:from typing import Self
@dataclass
class FileReader:
_fd: int
@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path))
Теперь создавайте объект так:
FileReader.open("file.txt")
, а не через __init__
.Это решение поддерживает:
from_fd
, from_buffer
, from_resource
, ...)NewType
:from typing import NewType
FileDescriptor = NewType("FileDescriptor", int)
Используйте в классе:
@dataclass
class FileReader:
_fd: FileDescriptor
@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path)) # пусть возвращает FileDescriptor
1. Используйте
@dataclass
.2. Не пишите
__init__
вручную.3. Добавляйте
@classmethod
-фабрики (.open()
, .from_config()
, .from_env()
).4. Используйте
NewType
.Библиотека питониста #буст